<template>
  <a-card :bordered="false">
    <a-row>
      <a-col>
        <a-form-model layout="inline" :model="model" @submit="handleSubmit" @submit.native.prevent>
         
          <a-form-model-item>
            <a-select v-model="model.configId" :disabled="isConnect"  style="width: 320px" @change="handleChange">
              <a-select-option v-for="item in esOptions" :key="item.id" :value=item.id>
              {{ item.label }}
              </a-select-option>
            </a-select>
          </a-form-model-item>
          <a-form-model-item>
            <a-button
              v-if="!isConnect"
              :loading="loading"
              type="primary"
              html-type="submit"
              :disabled="model.index === '' || model.esUrl === ''"
            >
              连接
            </a-button>
            <a-button v-else type="danger" ghost @click="handleDisconnect"> 断开连接 </a-button>
           
          </a-form-model-item>
        </a-form-model>
      </a-col>
      <a-col v-if="isConnect">
        <vxe-toolbar ref="xToolbar1" custom print>
          <template #buttons >
            <a-button style="margin-right: 15px" @click="handleAdd">添加</a-button>
            <a-button style="margin-right: 15px" v-if="selectedRows.length > 0" @click="handleDelete">删除</a-button>
            <a-button style="margin-right: 15px" @click="handleRefresh">刷新</a-button>
            <a-button style="margin-right: 15px" @click="handleAddMapping">添加列</a-button>
            <a-button style="margin-right: 15px" @click="handleExportXls(model.index)">下载模板</a-button>
            <a-button style="margin-right: 15px"  :loading="loading" @click="handleExportXls2(model.index)">导出</a-button></a-button>
            <a-upload
              name="file"
              :showUploadList="false"
              :multiple="true"
              :data="model"
              :headers="tokenHeader"
              :action="importExcelUrl"
              :beforeUpload="handleBeforeUpload"
             
              :customRequest="handleImport"

            >
           <!-- @change="handleImportExcel" -->
              <a-button type="primary" icon="import">导入</a-button>
            </a-upload>
          </template>
        </vxe-toolbar>
        <div>
          <a-input v-model="model.keyword" placeholder="搜索" @change="loadData"> </a-input>
        </div>
        <j-vxe-table
          ref="jvxetable"
          toolbar
          :toolbarConfig="toolbarConfig"
          row-number
          row-selection
          keep-source
          :height="340"
          :loading="loading"
          :columns="columns"
          :dataSource="dataSource"
          :pagination="pagination"
          @save="handleTableSave"
          @remove="handleTableRemove"
          @edit-closed="handleEditClosed"
          @pageChange="handlePageChange"
          @header-cell-click="headerCellClickEvent"
          @sort-change="sortChangeEvent4"
          @selectRowChange="handleSelectRowChange"
        >
          <template v-slot:toolbarSuffix>
            <!-- <a-button @click="handleAdd">添加</a-button>
            <a-button v-if="selectedRows.length > 0" @click="handleDelete">删除</a-button>
            <a-button @click="handleRefresh">刷新</a-button>
            <a-button @click="handleAddMapping">添加列</a-button>
            <a-button @click="handleExportXls(model.index)">下载模板</a-button>
            <a-upload
              name="file"
              :showUploadList="false"
              :multiple="false"
              :data="model"
              :headers="tokenHeader"
              :action="importExcelUrl"
              @change="handleImportExcel"
            >
              <a-button type="primary" icon="import">导入</a-button>
            </a-upload> -->
          </template>
        </j-vxe-table>
      </a-col>
    </a-row>
    <dataBrowserModal ref="modalForm" @ok="handleRefresh"></dataBrowserModal>
    <mappingModal ref="mappingForm" @ok="handleRefreshFieled"></mappingModal>

    <!--
        【即时保存大体思路】：
        1. JVxeTable 上必须加 keep-source 属性
        2. 监听 edit-closed事件，这个事件是在编辑完成后触发
        3. 在这个事件里面判断数据是否更改，如果更改了就调用接口进行保存操作
      -->
  </a-card>
</template>
  
  <script>
import VJsoneditor from 'v-jsoneditor'
import { searchAfter } from './js/fetchData'
import vueJsonEditor from 'vue-json-editor'
import { getAction, postAction, putAction, deleteAction, downFile, uploadAction } from '@api/manage'
import { JVXETypes } from '@/components/jeecg/JVxeTable'
import dataBrowserModal from './module/dataBrowserModal.vue'
import mappingModal from './module/mappingModal.vue'
import * as XLSX from 'xlsx'
import { resolve } from 'vue-json-editor/assets/jsoneditor'
const fieldsConversion = {
  text: 'input',
  float: 'input',
  date: 'datetime',
  long: 'input',
  boolean: 'select',
  integer: 'input',
  object: 'inputJOSN',
  keyword: 'input',
}
// 即时保存示例
export default {
  name: 'JSBCDemo',
  components: {
    dataBrowserModal,
    VJsoneditor,
    vueJsonEditor,
    mappingModal,
  },
  data() {
    return {
      model: {
        keyword: '',
      },
      esOptions: [],
      mappings: {},
      esName: '',

      isConnect: false,
      objectFieldArr: [],
      // 工具栏的按钮配置
      toolbarConfig: {
        // add 新增按钮；remove 删除按钮；clearSelection 清空选择按钮
        btn: [],
        slots: ['prefix', 'suffix'],
      },
      tokenHeader: {},

      // 是否正在加载
      loading: false,
      // 分页器参数
      pagination: {
        // 当前页码
        current: 1,
        // 每页的条数
        pageSize: 200,
        // 可切换的条数
        pageSizeOptions: ['10', '20', '30', '100', '200'],
        // 数据总数（目前并不知道真实的总数，所以先填写0，在后台查出来后再赋值）
        total: 0,
      },
      // 选择的行
      selectedRows: [],
      // 数据源，控制表格的数据
      dataSource: [],
      // 列配置，控制表格显示的列
      columns: [],
      json: [],
      // 查询url地址
      url: {
        esList: '/config/esConfig/list',
        getData: '/es/getData',
        mappings: '/es/getFieldMappings',
        // 模拟保存单行数据（即时保存）
        saveRow: '/es/update',
        delete: '/es/delete',
        downUrl: '/es/download-excel',
        // 模拟保存整个表格的数据
        saveAll: '/mock/vxe/immediateSaveAll',
        refresh: '/es/achievement_index/_refresh',
        importExcelUrl: 'es/importExcel',
        exportUrl: '/es/export',
      },
      indeterminate: true,
      checkAll: false,
      checkedList: [],
      plainOptions: ['id'],
    }
  },
  created() {
    this.initESList()
  },
  computed: {
    importExcelUrl: function () {
      const a = `${window._CONFIG['domianURL']}${this.url.importExcelUrl}`
      console.log('aaaaaaa', a)
      return a
    },
  },
  watch: {
    isConnect(newVal) {
      if (newVal) {
        this.connectTable()
      }
    },
  },
  methods: {
    initESList() {
      let param = {
        pageNo: 1,
        pageSize: 1000,
      }
      getAction(this.url.esList).then((res) => {
        if (res.success) {
          this.esOptions = res.result.records
        }
      })
    },
    handleSubmit() {
      this.loadFeild()
    },
    sortChangeEvent4() {
      console.log('触发排序')
    },
    connectTable() {
      this.$nextTick(() => {
        // 手动将表格和工具栏进行关联
        this.$refs.jvxetable.connect(this.$refs.xToolbar1)
      })
    },
    flatten(data) {
      const result = {}

      function recurse(cur, prop = '') {
        if (Object(cur) !== cur) {
          result[prop] = cur
        } else if (Array.isArray(cur)) {
          result[prop] = JSON.stringify(cur)
        } else {
          let isEmpty = true
          Object.keys(cur).forEach((p) => {
            isEmpty = false
            recurse(cur[p], prop ? `${prop}.${p}` : p)
          })
          if (isEmpty && prop) {
            result[prop] = {}
          }
        }
      }

      recurse(data)
      return result
    },
    headerCellClickEvent() {},
    handleChange() {},
    async getSearch() {
      let that = this
      let obj = this.esOptions.find((e) => e.id == this.model.configId)
      // let a = await searchAfter(this.model.configId, this.pagination.total)
      // console.log(a)
      this.loading = true
      const { data, searchAfterid } = await searchAfter(this.model.configId, this.pagination.total)

      const flattenData = data.map((item) => that.flatten(item))
      let visibleColumns = that.columns.map((e) => {
        return e.key
      })
      // const newData = unparse({
      //   fields: visibleColumns,
      //   data: flattenData,
      // })
      that.downloadExcel(flattenData, visibleColumns, obj.label)
      this.loading = false
    },
    getResponses(res) {
      const result = JSON.parse(res)
      return result && result.responses && result.responses[0]
    },
    downloadExcel(data, columns, filename) {
      const worksheet = XLSX.utils.json_to_sheet(data, { header: columns })
      const workbook = XLSX.utils.book_new()
      XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1')
      XLSX.writeFile(workbook, `${filename}.xlsx`)
    },
    // 加载数据
    loadData() {
      // 封装查询条件
      let formData = {
        ...this.model,

        pageNo: this.pagination.current,
        pageSize: this.pagination.pageSize,
      }
      // 调用查询数据接口

      this.loading = true
      getAction(this.url.getData, formData)
        .then((res) => {
          if (res.success) {
            try {
              const result = JSON.parse(res.result)
              this.pagination.total = result.hits.total.value
              console.log(result)

              this.dataSource = result.hits.hits.map((e) => {
                let highlight = this.buildLight(e.highlight)
                return {
                  id: e._id,
                  index: e._index,
                  score: e._score,

                  ...e._source,
                  ...highlight,
                  // obj: JSON.stringify(e._source.obj),
                }
              })
              console.log('请求', this.dataSource.length)
            } catch (e) {
              console.error('JSON 解析错误:', e.message)
            }
            this.isConnect = true
          }
        })
        .finally(() => {
          // 这里是无论成功或失败都会执行的方法，在这里关闭loading

          this.loading = false
        })
    },
    buildLight(highlight) {
      let obj = {}
      for (let key in highlight) {
        obj[key] = highlight[key].join('')
      }
      return obj
    },
    isObject(variable) {
      return (
        variable !== null && typeof variable === 'object' && !Array.isArray(variable) && !(variable instanceof Date)
      )
    },
    loadFeild() {
      let that = this
      let formData = {
        ...this.model,
      }
      getAction(this.url.mappings, formData)
        .then((res) => {
          if (res.success) {
            let arr = []
            let columns = res.result.properties
            this.mappings = res.result.properties

            this.json = res.result.json ? JSON.parse(res.result.json) : []

            for (let key in columns) {
              const obj = {
                key: key,
                type: JVXETypes[this.returnType(columns[key].type ? columns[key].type : 'object')],
                title: this.findMapping(key),
                width: '600px',
                visible: true,
                sortable: true,
                // slotName: columns[key].type ? null : key,
                dateFormat: columns[key].type == 'date' ? 'YYYY-MM-DD' : null,
                valueFormat: columns[key].type == 'date' ? 'YYYY-MM-DD' : null,
                formatter: ({ row, column, cellValue, index }) => {
                  return that.isObject(cellValue) ? JSON.stringify(cellValue) : cellValue
                },

                options:
                  columns[key].type == 'boolean'
                    ? [
                        { title: 'true', value: true },
                        { title: 'false', value: false },
                      ]
                    : null,
              }
              arr.push(obj)
              this.plainOptions.push(key)

              if (columns[key].properties) {
                this.objectFieldArr.push(key)
              }
            }
            this.columns = arr
            console.log(this.columns)
          }
        })
        .finally(() => {
          // 这里是无论成功或失败都会执行的方法，在这里关闭loading
          this.loadData()
        })
    },
    findMapping(key) {
      let result = this.json.find((e) => {
        return e.label == key
      })
      console.log('result', result, key)

      return result.value ? result.value : result.label
    },
    returnType(type) {
      return fieldsConversion[type]
    },
    formatter({ row, column, cellValue, index }) {
      return cellValue ? JSON.stringify(cellValue) : ''
    },
    // 【整体保存】点击保存按钮时触发的事件
    handleTableSave({ $table, target }) {
      // 校验整个表格
      $table.validate().then((errMap) => {
        // 校验通过
        if (!errMap) {
          // 获取所有数据
          let tableData = target.getTableData()
          console.log('当前保存的数据是：', tableData)
          // 获取新增的数据
          let newData = target.getNewData()
          console.log('-- 新增的数据：', newData)
          // 获取删除的数据
          let deleteData = target.getDeleteData()
          console.log('-- 删除的数据：', deleteData)

          // 【模拟保存】
          this.loading = true
          postAction(this.url.saveAll, tableData)
            .then((res) => {
              if (res.success) {
                this.$message.success(`保存成功！`)
              } else {
                this.$message.warn(`保存失败：` + res.message)
              }
            })
            .finally(() => {
              this.loading = false
            })
        }
      })
    },

    // 触发单元格删除事件
    handleTableRemove(event) {
      // 把 event.deleteRows 传给后台进行删除（注意：这里不会传递前端逻辑新增的数据，因为不需要请求后台删除）
      console.log('待删除的数据: ', event.deleteRows)
      // 也可以只传ID，因为可以根据ID删除
      let deleteIds = event.deleteRows.map((row) => row.id)
      console.log('待删除的数据ids: ', deleteIds)

      // 模拟请求后台删除
      this.loading = true
      window.setTimeout(() => {
        this.loading = false
        this.$message.success('删除成功')
        // 假设后台返回删除成功，必须要调用 confirmRemove() 方法，才会真正在表格里移除（会同时删除选中的逻辑新增的数据）
        event.confirmRemove()
      }, 1000)
    },

    // 单元格编辑完成之后触发的事件
    handleEditClosed(event) {
      let { $table, row, column } = event

      let field = column.property
      let cellValue = row[field]
      // 判断单元格值是否被修改
      if ($table.isUpdateByRow(row, field)) {
        // 校验当前行
        $table.validate(row).then((errMap) => {
          // 校验通过
          if (!errMap) {
            // 【模拟保存】
            let hideLoading = this.$message.loading(`正在保存"${column.title}"`, 0)
            console.log('即时保存数据：', row)
            row.configId = this.model.configId

            putAction(this.url.saveRow, row)
              .then((res) => {
                if (res.success) {
                  this.$message.success(`"${column.title}"保存成功！`)
                  // 局部更新单元格为已保存状态
                  $table.reloadRow(row, null, field)
                } else {
                  this.$message.warn(`"${column.title}"保存失败：` + res.message)
                }
              })
              .finally(() => {
                hideLoading()
              })
          }
        })
      }
    },

    // 当分页参数变化时触发的事件
    handlePageChange(event) {
      // 重新赋值
      this.pagination.current = event.current
      this.pagination.pageSize = event.pageSize
      // 查询数据
      this.loadData()
    },

    // 当选择的行变化时触发的事件
    handleSelectRowChange(event) {
      this.selectedRows = event.selectedRows
    },
    handleTableGet() {
      console.log(this.$refs.jvxetable)
    },
    handleAllocationp(e) {
      this.refreshColumn(e)
    },
    onCheckAllChange(e) {
      Object.assign(this, {
        checkedList: e.target.checked ? this.plainOptions : [],
        indeterminate: false,
        checkAll: e.target.checked,
      })
    },
    handleAllocationpSave(e) {
      //   this.refreshColumn(e)
      //   console.log(this.$refs.jvxetable)
    },
    refreshColumn(arr) {
      console.log(arr)
      const columns = this.$refs.jvxetable.getColumns()
      columns.forEach((e) => {
        if (!arr.includes(e.key)) {
          this.$refs.jvxetable.hideColumn(e.key)
        }
      })

      //   this.$refs.jvxetable.refreshColumn()
    },
    handleAdd() {
      this.$refs.modalForm.add(this.model.configId, this.mappings)
      this.$refs.modalForm.title = '新增'
      this.$refs.modalForm.disableSubmit = false
    },
    handleAddMapping() {
      this.$refs.mappingForm.add(this.model.configId, this.mappings)
      this.$refs.mappingForm.title = '新增'
      this.$refs.mappingForm.disableSubmit = false
    },
    handleDisconnect() {
      this.model = {
        keyword: '',
      }
      this.columns = []
      this.dataSource = []
      this.isConnect = false
    },
    test(e) {
      console.log(e)
    },
    handleTest(e) {
      console.log(e)
    },
    handleDelete() {
      let arr = this.selectedRows.map((e) => e.id)

      let formData = {
        configId: this.model.configId,
        documentId: arr.join(','),
      }
      deleteAction(this.url.delete, formData)
        .then((res) => {
          if (res.success) {
            this.selectedRows = []
            this.$message.success('删除成功！')
          }
        })
        .finally(() => {
          this.handleRefresh()
        })
    },
    handleRefresh() {
      let url = `/es/${this.model.configId}/_refresh`
      postAction(url).then((res) => {
        this.loadData()
      })
      // console.log(this.$refs.jvxetable.refreshData)
    },
    handleRefreshFieled() {
      let url = `/es/${this.model.configId}/_refresh`
      postAction(url).then((res) => {
        this.loadFeild()
      })
    },
    handleExportXls(fileName) {
      if (!fileName || typeof fileName != 'string') {
        fileName = '导出文件'
      }
      let param = {
        ...this.model,
      }

      downFile(this.url.downUrl, param).then((data) => {
        if (!data) {
          this.$message.warning('文件下载失败')
          return
        }
        if (typeof window.navigator.msSaveBlob !== 'undefined') {
          window.navigator.msSaveBlob(new Blob([data], { type: 'application/vnd.ms-excel' }), fileName + '.xls')
        } else {
          let url = window.URL.createObjectURL(new Blob([data], { type: 'application/vnd.ms-excel' }))
          let link = document.createElement('a')
          link.style.display = 'none'
          link.href = url
          link.setAttribute('download', fileName + '.xls')
          document.body.appendChild(link)
          link.click()
          document.body.removeChild(link) //下载完成移除元素
          window.URL.revokeObjectURL(url) //释放掉blob对象
        }
      })
    },
    handleExportXls2(fileName) {
      this.getSearch()
    },
    handleBeforeUpload(file, fileList) {
      let that = this

      let index = fileList.findIndex((item) => item.uid == file.uid)
      console.log('名字-----------', file.name)
      if (index == fileList.length - 1) {
        that.handleImport(fileList)
      }

      return new Promise((resolve, reject) => {
        return reject(false)
      })
    },
    async handleImport(fileList) {
      let that = this
      console.log(that.uploadFile)
      this.loading = true
      try {
        await fileList.reduce(async (promise, file) => {
          await promise
          return that.uploadFile(file)
        }, Promise.resolve())
        that.$message.success(`所有文件上传成功`)
        that.loading = false
        that.handleRefresh()
      } catch (error) {
        that.$message.warning(`文件上传失败：${error}`)
        that.loading = false
      }
    },
    uploadFile(file) {
      const formData = new FormData()
      formData.append('file', file)
      formData.append('configId', this.model.configId)
      return uploadAction(this.url.importExcelUrl, formData)
      // uploadAction(this.url.importExcelUrl,formData).then(res =>{
      //   if (res.code == 200) {
      //     this.$message.success(`${info.file.name} 文件上传成功`);
      //   }

      //   console.log(res);
      // })
    },
    handleImportExcel(info) {
      this.loading = true
      if (info.file.status !== 'uploading') {
        console.log(info.file, info.fileList)
      }
      if (info.file.status === 'done') {
        this.loading = false
        if (info.file.response.success) {
          // this.$message.success(`${info.file.name} 文件上传成功`);
          if (info.file.response.code === 201) {
            let {
              message,
              result: { msg, fileUrl, fileName },
            } = info.file.response
            let href = window._CONFIG['domianURL'] + fileUrl
            this.$warning({
              title: message,
              content: (
                <div>
                  <span>{msg}</span>
                  <br />
                  <span>
                    具体详情请{' '}
                    <a href={href} target="_blank" download={fileName}>
                      点击下载
                    </a>{' '}
                  </span>
                </div>
              ),
            })
          } else {
            this.$message.success(info.file.response.message || `${info.file.name} 文件上传成功`)
          }
          this.handleRefresh()
        } else {
          this.$message.error(`${info.file.name} ${info.file.response.message}.`)
        }
      } else if (info.file.status === 'error') {
        this.loading = false
        if (info.file.response.status === 500) {
          let data = info.file.response
          const token = Vue.ls.get(ACCESS_TOKEN)
          if (token && data.message.includes('Token失效')) {
            this.$error({
              title: '登录已过期',
              content: '很抱歉，登录已过期，请重新登录',
              okText: '重新登录',
              mask: false,
              onOk: () => {
                store.dispatch('Logout').then(() => {
                  Vue.ls.remove(ACCESS_TOKEN)
                  window.location.reload()
                })
              },
            })
          }
        } else {
          this.$message.error(`文件上传失败: ${info.file.msg} `)
        }
      }
    },
  },
}
</script>
  
  <style scoped>
</style>